package sanduche.controllers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import models.CalificacionPeriodo;
import models.Colegio;
import models.Curso;
import models.Estudiante;
import models.Grado;
import models.Indicador;
import models.IndicadorEstudiantePeriodo;
import models.IndicadorEstudiantePeriodoId;
import models.IndicadorId;
import models.Materia;
import models.MateriaCurso;
import models.MateriaGrado;
import models.Profesor;
import play.db.jpa.Transactional;
import play.libs.Json;
import play.mvc.Http.Session;
import sanduche.play.shared.ModuleConfig;
import sanduche.play.shared.RequestBody;
import sanduche.play.shared.RequestMethod;
import sanduche.play.shared.Route;
import sanduche.play.shared.UrlParam;
import services.ColegioSrv;
import services.DAO;
import services.ProfesorSrv;
import util.SessionObj;
import enums.CategoriaIndicador;

@ModuleConfig(prefix = "/api/profesor")
public class ProfesorController {

	private static SessionObj getSessionObj(Session session) {
		String json = session.get(UserController.SESSION_OBJ);
		if (json != null)
			return Json.fromJson(Json.parse(json), SessionObj.class);
		return null;
	}

	@Transactional(readOnly = true)
	@Route(value = "/materia_curso", method = RequestMethod.GET, iteratedClass = MateriaCurso.class)
	public static List<MateriaCurso> getMisAsignaturas(Session session) {

		List<MateriaCurso> asignaturas = ProfesorSrv.getAsignaturasProfesor(
				getSessionObj(session).getProfesor().getId(),
				ColegioSrv.getColegio(
						getSessionObj(session).getProfesor().getIdColegio())
						.getIdCalendarioAcademicoActual());

		return asignaturas;
	}

	@Transactional(readOnly = true)
	@Route(value = "/materia_curso", method = RequestMethod.GET, iteratedClass = MateriaCurso.class)
	public static List<CalificacionPeriodo> getCalificacionesPeriodo(
			Session session, @UrlParam("idMateria") Long idMateria,
			@UrlParam("idCurso") Long idCurso) {

		return ProfesorSrv.getCalificacionesPeriodo(
				idMateria,
				idCurso,
				ColegioSrv.getColegio(
						getSessionObj(session).getProfesor().getIdColegio())
						.getIdCalendarioAcademicoActual());
	}

	@Transactional(readOnly = true)
	@Route(value = "/calificacion_periodo", method = RequestMethod.GET, iteratedClass = CalificacionPeriodo.class)
	public static List<CalificacionPeriodo> getCalificacionesPeriodos(
			Session session, @UrlParam("idMateria") Long idMateria,
			@UrlParam("idCurso") Long idCurso) {

		Colegio colegio = ColegioSrv.getColegio(getSessionObj(session)
				.getProfesor().getIdColegio());
		List<CalificacionPeriodo> calificacionesPeriodo = ProfesorSrv
				.getCalificacionesPeriodos(idMateria, idCurso,
						colegio.getIdCalendarioAcademicoActual(),
						colegio.getIdPeriodoActual());
		return calificacionesPeriodo;
	}

	@Transactional(readOnly = true)
	@Route(value = "/materia_grado", method = RequestMethod.GET, iteratedClass = MateriaGrado.class)
	public static List<MateriaGrado> getMateriasGrado(Session session) {

		return ProfesorSrv.getMateriasGrado(
				ColegioSrv.getColegio(
						getSessionObj(session).getProfesor().getIdColegio())
						.getIdCalendarioAcademicoActual(),
				getSessionObj(session).getProfesor().getId());
	}

	@Transactional(readOnly = true)
	@Route(value = "/indicador", method = RequestMethod.GET, iteratedClass = Indicador.class)
	public static List<Indicador> getIndicadores(Session session,
			@UrlParam("idMateria") Long idMateria,
			@UrlParam("idGrado") Long idGrado) {
		Long idPeriodo = ColegioSrv.getColegio(
				getSessionObj(session).getProfesor().getIdColegio())
				.getIdPeriodoActual();
		List<Indicador> inds = DAO
				.execute(
						"SELECT i FROM Indicador i WHERE i.idMateria = :idMateria AND i.idGrado = :idGrado AND i.idPeriodo = :idPeriodo",
						-1, "idMateria", idMateria, "idGrado", idGrado,
						"idPeriodo", idPeriodo);

		Map<CategoriaIndicador, List<Indicador>> indicadores = new HashMap<CategoriaIndicador, List<Indicador>>();
		for (CategoriaIndicador c : CategoriaIndicador.values())
			indicadores.put(c, new ArrayList<Indicador>());

		for (Indicador i : inds)
			indicadores.get(i.getCategoria()).add(i);
		return inds;
	}

	@Transactional
	@Route(value = "/indicador/:idMateria/:idGrado", method = RequestMethod.POST)
	public static Indicador newIndicador(Session session,
			@RequestBody Indicador i, @UrlParam("idMateria") Long idMateria,
			@UrlParam("idGrado") Long idGrado) throws Exception {
		Long idPeriodo = ColegioSrv.getColegio(
				getSessionObj(session).getProfesor().getIdColegio())
				.getIdPeriodoActual();
		checkColegio(session, idMateria, idGrado);
		i.setIdMateria(idMateria);
		i.setIdGrado(idGrado);
		i.setIdPeriodo(idPeriodo);

		i.generateConsecutivo();
		DAO.persist(i);
		return i;
	}

	@Transactional
	@Route(value = "/indicador/:idMateria/:idGrado", method = RequestMethod.PUT)
	public static void updateIndicador(Session session,
			@RequestBody Indicador i, @UrlParam("idMateria") Long idMateria,
			@UrlParam("idGrado") Long idGrado,
			@UrlParam("categoria") String categoria,
			@UrlParam("consecutivo") Integer consecutivo) throws Exception {
		checkColegio(session, idMateria, idGrado);

		Long idPeriodo = ColegioSrv.getColegio(
				getSessionObj(session).getProfesor().getIdColegio())
				.getIdPeriodoActual();

		i.setIdPeriodo(idPeriodo);
		DAO.merge(i);

	}

	@Transactional
	@Route(value = "/indicador/:idMateria/:idGrado/:categoria/:consecutivo", method = RequestMethod.DELETE)
	public static void deleteIndicador(Session session,
			@UrlParam("idMateria") Long idMateria,
			@UrlParam("idGrado") Long idGrado,
			@UrlParam("categoria") String categoria,
			@UrlParam("consecutivo") Integer consecutivo) throws Exception {
		checkColegio(session, idMateria, idGrado);

		Long idPeriodo = ColegioSrv.getColegio(
				getSessionObj(session).getProfesor().getIdColegio())
				.getIdPeriodoActual();
		Indicador old = DAO.find(Indicador.class, new IndicadorId(idMateria,
				idGrado, idPeriodo, CategoriaIndicador.valueOf(categoria),
				consecutivo));

		if (old != null)
			DAO.remove(old);

	}

	@Transactional(readOnly = true)
	@Route(value = "/curso/:idCurso", method = RequestMethod.GET)
	public static Curso getCurso(@UrlParam("idCurso") Long idCurso) {
		Curso curso = DAO.find(Curso.class, idCurso);
		return curso;
	}

	@Transactional(readOnly = true)
	@Route(value = "/estudiante", method = RequestMethod.GET, iteratedClass = Estudiante.class)
	public static List<Estudiante> getEstudiantesCurso(
			@UrlParam("idCurso") Long idCurso) {
		return ProfesorSrv.getEstudiantesCurso(idCurso);
	}

	@Transactional(readOnly = true)
	@Route(value = "/indicador_estudiante_periodo/:idCurso/:idMateria", method = RequestMethod.GET, iteratedClass = IndicadorEstudiantePeriodo.class)
	public static List<IndicadorEstudiantePeriodo> getIndicadoresEstudiantes(
			Session session, @UrlParam("idCurso") Long idCurso,
			@UrlParam("idMateria") Long idMateria) {
		Curso curso = DAO.find(Curso.class, idCurso);
		Long idPeriodoActual = ColegioSrv.getColegio(
				getSessionObj(session).getProfesor().getIdColegio())
				.getIdPeriodoActual();
		List<IndicadorEstudiantePeriodo> res = DAO
				.execute(
						"SELECT c FROM IndicadorEstudiantePeriodo c WHERE c.idMateria = :idMateria AND c.idGrado = :idGrado AND c.idPeriodo = :idPeriodo",
						-1, "idMateria", idMateria, "idGrado",
						curso.getIdGrado(), "idPeriodo", idPeriodoActual);
		return res;
	}

	@Transactional
	@Route(value = "/indicador_estudiante_periodo", method = RequestMethod.PUT)
	public static IndicadorEstudiantePeriodo newIndicadorEstudiante(
			Session session, @RequestBody IndicadorEstudiantePeriodo ic) {

		ic.setIdPeriodo(ColegioSrv.getColegio(
				getSessionObj(session).getProfesor().getIdColegio())
				.getIdPeriodoActual());
		DAO.merge(ic);
		return ic;
	}

	@Transactional
	@Route(value = "/indicador_estudiante_periodo/:idEstudiante/:idMateria/:idGrado/:categoria/:consecutivo", method = RequestMethod.DELETE)
	public static void deleteIndicadorEstudiante(Session session,
			@UrlParam("idEstudiante") Long idEstudiante,
			@UrlParam("idMateria") Long idMateria,
			@UrlParam("idGrado") Long idGrado,
			@UrlParam("categoria") String categoriaIndicador,
			@UrlParam("consecutivo") Integer consecutivoIndicador) {
		Long idPeriodoActual = ColegioSrv.getColegio(
				getSessionObj(session).getProfesor().getIdColegio())
				.getIdPeriodoActual();
		IndicadorEstudiantePeriodoId id = new IndicadorEstudiantePeriodoId(
				idEstudiante, idMateria, idGrado, idPeriodoActual,
				CategoriaIndicador.valueOf(categoriaIndicador),
				consecutivoIndicador);
		IndicadorEstudiantePeriodo ic = DAO.find(
				IndicadorEstudiantePeriodo.class, id);
		DAO.remove(ic);

	}

	@Transactional
	@Route(value = "/calificacion_periodo", method = RequestMethod.PUT)
	public static CalificacionPeriodo setCalificacionPeriodo(Session session,
			@RequestBody CalificacionPeriodo ic) {

		ic.setIdPeriodo(ColegioSrv.getColegio(
				getSessionObj(session).getProfesor().getIdColegio())
				.getIdPeriodoActual());
		DAO.merge(ic);
		return ic;
	}

	@Transactional(readOnly = true)
	@Route(value = "/materia", method = RequestMethod.GET, iteratedClass = Materia.class)
	public static List<Materia> getMaterias(Session session) {
		return ColegioSrv.getMateriasColegio(getSessionObj(session)
				.getProfesor().getIdColegio());
	}

	@Transactional(readOnly = true)
	@Route(value = "/grado", method = RequestMethod.GET, iteratedClass = Grado.class)
	public static List<Grado> getGrados(Session session) {

		return ColegioSrv.getGradosColegio(getSessionObj(session).getProfesor()
				.getIdColegio());
	}

	@Transactional(readOnly = true)
	@Route(value = "/self", method = RequestMethod.GET)
	public static Profesor getMyInfo(Session session) {
		return DAO.find(Profesor.class, getSessionObj(session).getProfesor()
				.getId());
	}

	@Transactional(readOnly = true)
	@Route(value = "/curso", method = RequestMethod.GET, iteratedClass = Curso.class)
	public static List<Curso> getCursos(Session session) {
		System.out.println("Id profesor: "
				+ getSessionObj(session).getProfesor().getId());
		String s = "SELECT DISTINCT c FROM Curso c, MateriaCurso mc WHERE c.id = mc.idCurso AND mc.profesor.id = :idProfesor AND c.idCalendarioAcademico = :idCalendarioAcademico";
		List<Curso> res = DAO.execute(
				s,
				-1,
				"idProfesor",
				getSessionObj(session).getProfesor().getId(),
				"idCalendarioAcademico",
				ColegioSrv.getColegio(
						getSessionObj(session).getProfesor().getIdColegio())
						.getIdCalendarioAcademicoActual());
		return res;
	}

	private static void checkColegio(Session session,
			@UrlParam("idMateria") Long idMateria,
			@UrlParam("idGrado") Long idGrado) throws Exception {
		Materia m = DAO.find(Materia.class, idMateria);
		if (m == null
				|| !m.getIdColegio().equals(
						getSessionObj(session).getProfesor().getIdColegio()))
			throw new Exception("No tiene permisos sobre este recurso");
		Grado g = DAO.find(Grado.class, idGrado);
		if (g == null
				|| !g.getIdColegio().equals(
						getSessionObj(session).getProfesor().getIdColegio()))
			throw new Exception("No tiene permisos sobre este recurso");

	}

}
